<?php
/**
 * PsiFramework
 *
 * Php Simple Framework
 *
 * PHP version 5.3
 *
 * @category  PsiFramework.Plugins.Shop.Classes.DAO
 * @package   PsiFramework.Plugins.Shop.Classes.DAO
 * @author    Remi San <remi.san@gmail.com>
 * @copyright 2011 Remi San
 * @license   http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @version   SVN: <svn_id>
 * @link      http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Shop\Classes\DAO\DiscountDAO.html
 */

namespace PsiFramework\Plugins\Shop\Classes\DAO;

import("Classes.DAO.AbstractDAO");
import("Classes.Util.Parameters.ObjectParameters");

use \PsiFramework\Classes\DAO\AbstractDAO;
use \PsiFramework\Classes\Model\Object;
use \PsiFramework\Classes\Util\Parameters\ObjectParameters;
use \PsiFramework\Plugins\Shop\Classes\Model\Discount;
use \PsiFramework\Classes\Util\Database\Query\SqlOperation;
use \PsiFramework\Classes\Util\Database\Query\SqlColumn;
use \PsiFramework\Classes\Util\Database\Query\SqlValue;
use \PsiFramework\Classes\Util\Database\Filters\QueryFilter;


/**
 * The Discount Data Access Object
 *
 * This is the default class for the Discount Data Access Object
 *
 * @category PsiFramework.Plugins.Shop.Classes.DAO
 * @package  PsiFramework.Plugins.Shop.Classes.DAO
 * @author   Remi San <remi.san@gmail.com>
 * @license  http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @link     http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Shop\Classes\DAO\DiscountDAO.html
 */
class DiscountDAO extends AbstractDAO
{
    /**
     * The singleton
     * 
     * @var DiscountDAO
     */
    protected static     $_singleton = null;

    /**
     * OrderDAO constructor
     * 
     * @param ObjectParameters $objectParameters The object parameters
     * 
     * @return DiscountDAO
     */
    protected function __construct(
        ObjectParameters $objectParameters=null
    )
    {
        parent::__construct($objectParameters);
    }
    
    /**
     * The function that returns the quantity clause
     * 
     * @param int $quantity the quantity
     * 
     * @return SqlOperation
     */
    protected function getQuantityClause(/*int*/ $quantity)
    {
        $minQuantityCol = new SqlColumn('min_quantity');
        $maxQuantityCol = new SqlColumn('max_quantity');
        
        $quantityValue = new SqlValue((int)$quantity);
        
        $andQuantity = new SqlOperation(SqlOperation::$and);
        
        $nullMaxQuantity = new SqlOperation(SqlOperation::$isNull);
        $nullMaxQuantity->addParameter($maxQuantityCol);
        
        if (!is_null($quantity)) {
        	$minQuantityEqual = new SqlOperation(SqlOperation::$greaterThanOrEqual);
        	$minQuantityEqual->addParameter($quantityValue);
        	$minQuantityEqual->addParameter($minQuantityCol);
        
        	$maxQuantityEqual = new SqlOperation(SqlOperation::$lowerThanOrEqual);
        	$maxQuantityEqual->addParameter($quantityValue);
        	$maxQuantityEqual->addParameter($maxQuantityCol);
        
        	$orMaxQuantity = new SqlOperation(SqlOperation::$or);
        	$orMaxQuantity->addParameter($maxQuantityEqual);
        	$orMaxQuantity->addParameter($nullMaxQuantity);
        
        	$andQuantity->addParameter($minQuantityEqual);
        	$andQuantity->addParameter($orMaxQuantity);
        
        } else {
        	$nullMinQuantity = new SqlOperation(SqlOperation::$isNull);
        	$nullMinQuantity->addParameter($minQuantityCol);
        
        	$andQuantity->addParameter($nullMinQuantity);
        	$andQuantity->addParameter($nullMaxQuantity);
        }
        
        return $andQuantity;
    }
    
    /**
     * The function that returns the discounts offer for
     * the specified category with the specified quantity
     *
     * @param ItemCategory $category      The category
     * @param int          $quantity      The quantity
     * @param bool         $checkSecurity Check security ?
     *
     * @return Discount[]
     */
    public function getDiscountsByCategoryQuantity(
        /*ItemCategory*/ $category,
        /*int*/          $quantity,
        /*bool*/         $checkSecurity=true
    )
    {
    	if (is_null($category) || is_null($category->getId())) {
    		return array();
    	}
    
    	$itemCol = new SqlColumn('item_id');
    	$packageCol = new SqlColumn('package_id');
    	$categoryCol = new SqlColumn('category_id');
    	$nullValue = new SqlValue(null);
    
    	$nullItemEqual = new SqlOperation(SqlOperation::$isNull);
    	$nullItemEqual->addParameter($itemCol);
    
    	$nullPackageEqual = new SqlOperation(SqlOperation::$isNull);
    	$nullPackageEqual->addParameter($packageCol);
    
    	$nullCategoryEqual = new SqlOperation(SqlOperation::$isNull);
    	$nullCategoryEqual->addParameter($categoryCol);
    
    	$categoryOr = new SqlOperation(SqlOperation::$or);
    	$categoryOr->addParameter($nullCategoryEqual);
    
    	while ($category != null) {
    		$catEqual = new SqlOperation(SqlOperation::$equal);
    		$catEqual->addParameter($categoryCol);
    		$catEqual->addParameter(new SqlValue($category->getId()));
    
    		$categoryOr->addParameter($catEqual);
    		$category = $category->getParent();
    	}
    
    	$nullItemPackage = new SqlOperation(SqlOperation::$and);
    	$nullItemPackage->addParameter($nullItemEqual);
    	$nullItemPackage->addParameter($nullPackageEqual);
    	$nullItemPackage->addParameter($categoryOr);
    
    	$andQuantity = $this->getQuantityClause($quantity);
    
    	$and = new SqlOperation(SqlOperation::$and);
    	$and->addParameter($nullItemPackage);
    	$and->addParameter($andQuantity);
    
    	return $this->retrieveAll(new QueryFilter($and), null, $checkSecurity);
    }
    
    /**
     * The function that returns the discounts offer for
     * the specified item with the specified quantity
     * 
     * @param OrderItem $item          The item
     * @param int       $quantity      The quantity
     * @param bool      $checkSecurity Check security ?
     * 
     * @return Discount[]
     */
    public function getDiscountsByItemQuantity(
        /*OrderItem*/ $item,
        /*int*/       $quantity,
        /*bool*/      $checkSecurity=true
    )
    {
        if (is_null($item) || is_null($item->getId())) {
        	return array();
        }
        
        $itemCol = new SqlColumn('item_id');
        $packageCol = new SqlColumn('package_id');
        $categoryCol = new SqlColumn('category_id');
        
        $itemValue = new SqlValue($item->getId());
        $nullValue = new SqlValue(null);
        
        $itemEqual = new SqlOperation(SqlOperation::$equal);
        $itemEqual->addParameter($itemCol);
        $itemEqual->addParameter($itemValue);
                
        $nullItemEqual = new SqlOperation(SqlOperation::$isNull);
        $nullItemEqual->addParameter($itemCol);
        
        $nullPackageEqual = new SqlOperation(SqlOperation::$isNull);
        $nullPackageEqual->addParameter($packageCol);
        
        $nullCategoryEqual = new SqlOperation(SqlOperation::$isNull);
        $nullCategoryEqual->addParameter($categoryCol);
        
        $categoryOr = new SqlOperation(SqlOperation::$or);
        $categoryOr->addParameter($nullCategoryEqual);
        
        $category = $item->getCategory();
        while ($category != null) {
            $catEqual = new SqlOperation(SqlOperation::$equal);
            $catEqual->addParameter($categoryCol);
            $catEqual->addParameter(new SqlValue($category->getId()));
            
            $categoryOr->addParameter($catEqual);
            $category = $category->getParent();
        }
        
        $nullItemPackage = new SqlOperation(SqlOperation::$and);
        $nullItemPackage->addParameter($nullItemEqual);
        $nullItemPackage->addParameter($nullPackageEqual);
        $nullItemPackage->addParameter($categoryOr);
        
        $itemOr = new SqlOperation(SqlOperation::$or);
        $itemOr->addParameter($itemEqual);
        $itemOr->addParameter($nullItemPackage);
        
        $andQuantity = $this->getQuantityClause($quantity);
        
        $and = new SqlOperation(SqlOperation::$and);
        $and->addParameter($itemOr);
        $and->addParameter($andQuantity);
        
        return $this->retrieveAll(new QueryFilter($and), null, $checkSecurity);
    }
    
    /**
     * The function to call instead of the constructor.
     *
     *@param ObjectParameters $objectParameters the object parameters 
     *                                          for Order
     *
     * @return DiscountDAO instance
     */
    public static function getInstance(ObjectParameters $objectParameters)
    {

        if (self::$_singleton==null) {
            self::$_singleton = new DiscountDAO($objectParameters);
        }

        return self::$_singleton;
    }
}
